<template>
  <el-row :gutter="20">
    <el-col :span="16">
      <ContentWrap title="申请信息">
        <el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="80px">

          <el-form-item label="请假类型" prop="type">
            <el-select v-model="formData.type" placeholder="请选择请假类型">
              <el-option v-for="dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)" :key="dict.value"
                :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>

          <el-form-item label="开始时间" prop="startTime">
            <el-row :gutter="10">
              <el-col :span="16">
                <el-date-picker v-model="formData.startTime" type="date" value-format="YYYY-MM-DD" placeholder="选择开始时间" style="width: 100%" />
              </el-col>
              <el-col :span="8">
                <el-select v-model="formData.startType" placeholder="时间类型" prop="startType">
                  <el-option label="上午" :value="1" />
                  <el-option label="下午" :value="2" />
                </el-select>
              </el-col>
            </el-row>
          </el-form-item>
          <el-form-item label="结束时间" prop="endTime">
            <el-row :gutter="10">
              <el-col :span="16">
                <el-date-picker v-model="formData.endTime" type="date" value-format="YYYY-MM-DD" placeholder="选择结束时间" style="width: 100%" />
              </el-col>
              <el-col :span="8">
                <el-select v-model="formData.endType" placeholder="时间类型" prop="endType">
                  <el-option label="上午" :value="1" />
                  <el-option label="下午" :value="2" />
                </el-select>
              </el-col>
            </el-row>
          </el-form-item>
          
          <!-- <el-form-item label="申请时长" prop="calculatedDuration">
            <el-row :gutter="10">
              <el-col :span="12">
                <el-input v-model="calculatedDuration.day" disabled placeholder="自动计算天数" style="width: 100%" />
                <div style="text-align: center; color: #909399; font-size: 12px; margin-top: 4px;">天数</div>
              </el-col>
              <el-col :span="12">
                <el-input v-model="calculatedDuration.hours" disabled placeholder="0" style="width: 100%" />
                <div style="text-align: center; color: #909399; font-size: 12px; margin-top: 4px;">小时数</div>
              </el-col>
            </el-row>
          </el-form-item> -->
          
          <el-form-item label="请假原因" prop="reason">
            <el-input v-model="formData.reason" placeholder="请输入请假原因" :rows="4" type="textarea" />
          </el-form-item>
          <el-form-item label="相关文件">
            <OaFileManager :folderDisabled="true" @fileSelectSuccess="fileSelectScccess" />
 
          </el-form-item>
          <el-form-item>
            <el-button :disabled="formLoading" type="primary" @click="submitForm">
              确 定
            </el-button>
          </el-form-item>
        </el-form>
      </ContentWrap>
    </el-col>

    <!-- 右侧信息展示 -->
    <el-col :span="8">
      <!-- 假期余额信息 -->
      <ContentWrap title="我的假期结余" :bodyStyle="{ padding: '0 20px 0' }">
        <div v-loading="leaveBalanceLoading">
          <el-table :data="leaveBalanceList" style="width: 100%" size="small" :show-header="false">
            <el-table-column prop="leaveName" label="假期类型" width="80">
              <template #default="{ row }">
                <el-tag size="small" type="success">
                  {{ row.leaveName }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="remaining" label="剩余" align="right">
              <template #default="{ row }">
                <span :class="{ 'text-danger': row.remaining <= 0, 'text-success': row.remaining > 0 }">
                  {{ row.remaining }} {{ row.leaveName === '调休' ? '小时' : '天' }}
                </span>
              </template>
            </el-table-column>
          </el-table>
          <div v-if="leaveBalanceList.length === 0" style="text-align: center; color: #909399; padding: 20px 0;">
            暂无假期结余信息
          </div>
        </div>
      </ContentWrap>

      <!-- 审批相关：流程信息 -->
      <ContentWrap title="审批流程" :bodyStyle="{ padding: '0 20px 0' }">
        <ProcessInstanceTimeline ref="timelineRef" :activity-nodes="activityNodes" :show-status-icon="false"
          @select-user-confirm="selectUserConfirm" />
      </ContentWrap>
    </el-col>
  </el-row>
</template>
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { LeaveApplyApi, LeaveApplyVO, LeaveDurationCalcReqVO } from '@/api/oa/leaveapply'
import { useTagsViewStore } from '@/store/modules/tagsView'
import { useUserStore } from '@/store/modules/user'

// 审批相关：import
import * as DefinitionApi from '@/api/bpm/definition'
import ProcessInstanceTimeline from '@/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue'
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import { CandidateStrategy, NodeId } from '@/components/SimpleProcessDesignerV2/src/consts'
import { ApprovalNodeInfo } from '@/api/bpm/processInstance'
import { ref, watch, computed } from 'vue'
import dayjs from 'dayjs'

// 假期余额相关
import { EmployeeLeaveBalanceApi, EmployeeLeaveBalanceVO } from '@/api/oa/employeeleavebalance'
import OaFileManager from '@/components/Oa/OaFileManager.vue'

defineOptions({ name: 'OaLeaveApplyCreate' })

const message = useMessage() // 消息弹窗
const { delView } = useTagsViewStore() // 视图操作
const { push, currentRoute } = useRouter() // 路由
const userStore = useUserStore() // 用户信息

const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用

// 假期余额相关变量
const leaveBalanceLoading = ref(false) // 假期余额加载状态
const leaveBalanceList = ref<EmployeeLeaveBalanceVO[]>([]) // 假期余额列表

// 自动计算时长相关变量
const calculatedDuration = ref({
  day: 0,
  hours: 0
})

const todayStr = dayjs().format('YYYY-MM-DD')

const formData = ref<{ 
  type: number | undefined; 
  leaveName: string | undefined; 
  reason: string | undefined; 
  startTime: string; 
  startType: number | undefined;
  endTime: string; 
  endType: number | undefined;
  files: string | undefined 
}>({
  type: undefined,
  leaveName: undefined,
  reason: undefined,
  startTime: todayStr,
  startType: 1, // 默认上午
  endTime: todayStr,
  endType: 2, // 默认下午
  files: undefined
})

// 结束时间校验方法
// const validateEndTime = (_rule: any, value: any, callback: (error?: Error) => void) => {
//   if (!value || !formData.value.startTime) {
//     callback()
//     return
//   }
//   if (value < formData.value.startTime) {
//     callback(new Error('结束时间必须大于等于开始时间'))
//     return
//   }
//   if (value === formData.value.startTime && formData.value.endType && formData.value.startType && formData.value.endType <= formData.value.startType) {
//     callback(new Error('同一天时，结束时间类型必须晚于开始时间类型'))
//     return
//   }
//   callback()
// }
const formRules = reactive({
  type: [{ required: true, message: '请假类型不能为空', trigger: 'change' }],
  reason: [{ required: true, message: '请假原因不能为空', trigger: 'blur' }],
  startTime: [{ required: true, message: '开始时间不能为空', trigger: 'blur' }],
  startType: [{ required: true, message: '开始时间类型不能为空', trigger: 'change' }],
  endTime: [
    { required: true, message: '结束时间不能为空', trigger: 'blur' },
    // { validator: validateEndTime, trigger: 'blur' }
  ],
  endType: [{ required: true, message: '结束时间类型不能为空', trigger: 'change' }],
})
const formRef = ref() // 表单 Ref

// 审批相关：变量
const processDefineKey = 'oa_leave_apply' // 流程定义 Key
const startUserSelectTasks = ref<ApprovalNodeInfo[]>([]) // 发起人需要选择审批人的用户任务列表
const startUserSelectAssignees = ref<Record<string, any[]>>({}) // 发起人选择审批人的数据
const tempStartUserSelectAssignees = ref<Record<string, any[]>>({}) // 历史发起人选择审批人的数据，用于每次表单变更时，临时保存
const activityNodes = ref<ProcessInstanceApi.ApprovalNodeInfo[]>([]) // 审批节点信息
const processDefinitionId = ref('')
const fileDialogRef = ref()

/** 获取当前用户的假期余额 */
const getLeaveBalance = async () => {
  if (!userStore.user.id) {
    return
  }
  
  leaveBalanceLoading.value = true
  try {
    const currentYear = new Date().getFullYear()
    const params = {
      userId: userStore.user.id,
      years: currentYear, // 添加本年份条件
      pageSize: 100 // 获取足够多的数据
    }
    console.log('假期余额查询参数:', params) // 添加调试信息
    const result = await EmployeeLeaveBalanceApi.getEmployeeLeaveBalancePage(params)
    leaveBalanceList.value = result.list || []
  } catch (error) {
    console.error('获取假期余额失败:', error)
    message.error('获取假期余额失败')
  } finally {
    leaveBalanceLoading.value = false
  }
}

/** 提交表单 */
const submitForm = async () => {
  // 1.1 校验表单
  if (!formRef.value) return
  const valid = await formRef.value.validate()
  if (!valid) return
  // 1.2 审批相关：校验指定审批人
  if (startUserSelectTasks.value?.length > 0) {
    for (const userTask of startUserSelectTasks.value) {
      if (
        Array.isArray(startUserSelectAssignees.value[userTask.id]) &&
        startUserSelectAssignees.value[userTask.id].length === 0
      ) {
        return message.warning(`请选择\${userTask.name}的审批人`)
      }
    }
  }

  // 2. 提交请求
  formLoading.value = true
  try {
    const data = { 
      ...formData.value,
      day: calculatedDuration.value.day,
      hours: calculatedDuration.value.hours,
      startUserSelectAssignees: startUserSelectTasks.value?.length > 0 ? startUserSelectAssignees.value : undefined
    } as any
    await LeaveApplyApi.createLeaveApply(data)
    message.success('发起成功')
    // 关闭当前 Tab
    delView(unref(currentRoute))
    await push({ name: 'LeaveApply' })
  } finally {
    formLoading.value = false
  }
}
const fileSelectScccess = (fileIds: string[]) => {
  formData.value.files = fileIds.join(',')
}
/** 审批相关：获取审批详情 */
const getApprovalDetail = async () => {
  try {
    const data = await ProcessInstanceApi.getApprovalDetail({
      processDefinitionId: processDefinitionId.value,
      // TODO 小北：可以支持 processDefinitionKey 查询
      activityId: NodeId.START_USER_NODE_ID,
      processVariablesStr: JSON.stringify({ day: daysDifference() }) // 解决 GET 无法传递对象的问题，后端 String 再转 JSON
    })

    if (!data) {
      message.error('查询不到审批详情信息！')
      return
    }
    // 获取审批节点，显示 Timeline 的数据
    activityNodes.value = data.activityNodes

    // 获取发起人自选的任务
    startUserSelectTasks.value = data.activityNodes?.filter(
      (node: ApprovalNodeInfo) => CandidateStrategy.START_USER_SELECT === node.candidateStrategy
    ) || []
    // 恢复之前的选择审批人
    if (startUserSelectTasks.value?.length > 0) {
      for (const node of startUserSelectTasks.value) {
        const nodeId = node.id.toString()
        if (
          tempStartUserSelectAssignees.value[nodeId] &&
          tempStartUserSelectAssignees.value[nodeId].length > 0
        ) {
          startUserSelectAssignees.value[nodeId] = tempStartUserSelectAssignees.value[nodeId]
        } else {
          startUserSelectAssignees.value[nodeId] = []
        }
      }
    }
  } finally {
  }
}

/** 审批相关：选择发起人 */
const selectUserConfirm = (id: string, userList: any[]) => {
  startUserSelectAssignees.value[id] = userList?.map((item: any) => item.id)
}

// 计算天数差（用于流程变量）
const daysDifference = () => {
  return calculatedDuration.value.day
}

/** 初始化 */
onMounted(async () => {
  // 获取当前用户的假期余额
  await getLeaveBalance()
  
  // TODO @小北：这里可以简化，统一通过 getApprovalDetail 处理么？
  const processDefinitionDetail = await DefinitionApi.getProcessDefinition(
    undefined,
    processDefineKey
  )

  if (!processDefinitionDetail) {
    message.error('OA 请假申请的流程模型未配置，请检查！')
    return
  }
  processDefinitionId.value = processDefinitionDetail.id
  startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks

  // 审批相关：加载最新的审批详情，主要用于节点预测
  await getApprovalDetail()
})

/** 审批相关：预测流程节点会因为输入的参数值而产生新的预测结果值，所以需重新预测一次, formData.value可改成实际业务中的特定字段 */
watch(
  formData.value,
  (newValue, oldValue) => {
    if (!oldValue) {
      return
    }
    if (newValue && Object.keys(newValue).length > 0) {
      // 记录之前的节点审批人
      tempStartUserSelectAssignees.value = startUserSelectAssignees.value
      startUserSelectAssignees.value = {}
      // 加载最新的审批详情,主要用于节点预测
      getApprovalDetail()
    }
  },
  {
    immediate: true
  }
)

// 监听 type 变化，自动设置 leaveName
watch(
  () => formData.value.type,
  (newType) => {
    const dict = getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE).find(item => item.value === newType)
    formData.value.leaveName = dict ? dict.label : undefined
  }
)

const openFileDialog = () => {
  fileDialogRef.value.open()
}

 
</script>

<style lang="scss" scoped>
.text-danger {
  color: #f56c6c;
  font-weight: bold;
}

.text-success {
  color: #67c23a;
  font-weight: bold;
}

:deep(.el-table) {
  .el-table__row {
    .el-table__cell {
      padding: 8px 0;
    }
  }
}

:deep(.el-tag) {
  font-size: 12px;
  padding: 2px 6px;
}
</style>
